package cn.tedu.luban.worker.main.service;

import cn.tedu.luban.account.api.AccountApi;
import cn.tedu.luban.account.protocol.dto.AccountDTO;
import cn.tedu.luban.account.protocol.param.AccountCreateParam;
import cn.tedu.luban.attach.api.AttachApi;
import cn.tedu.luban.attach.protocol.dto.AttachDTO;
import cn.tedu.luban.attach.protocol.param.AttachUpdateParam;
import cn.tedu.luban.attach.protocol.query.AttachQuery;
import cn.tedu.luban.passport.protocol.jwt.UserPrinciple;
import cn.tedu.luban.passport.sdk.security.LubanSecurityContext;
import cn.tedu.luban.worker.common.enums.AuditStatusEnum;
import cn.tedu.luban.worker.common.enums.WorkerResultEnum;
import cn.tedu.luban.worker.main.converter.WorkerConverter;
import cn.tedu.luban.worker.main.repository.WorkerAreaRepository;
import cn.tedu.luban.worker.main.repository.WorkerAuditLogRepository;
import cn.tedu.luban.worker.main.repository.WorkerCategoryRepository;
import cn.tedu.luban.worker.main.repository.WorkerRepository;
import cn.tedu.luban.worker.protocol.bo.*;
import cn.tedu.luban.worker.protocol.param.AuditSubmitParam;
import cn.tedu.luban.worker.protocol.param.IdCardParam;
import cn.tedu.luban.worker.protocol.param.WorkerParam;
import cn.tedu.luban.worker.protocol.param.WorkerRegistParam;
import cn.tedu.luban.worker.protocol.query.WorkerListQuery;
import com.tedu.inn.protocol.ListRecordTotalBO;
import com.tedu.inn.protocol.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class WorkerService {

    @Autowired
    private WorkerRepository workerRepository;

    /**
     * 师傅入驻
     * @param param 注册信息
     * @return workerId
     */
    // 事务一致性
    @Transactional(rollbackFor = Exception.class)
    public Long workerCreate(WorkerRegistParam param) throws BusinessException {
        // 1.获取当前登录的用户id
        Long userId = getUserId();
        param.setUserId(userId);
        // 2.验证身份证和人名(实名认证)
        checkIDCard();
        // 3.存储param中的师傅数据 worker
        Long workerId = saveWorker(param);
        // 4.存储param中的师傅服务区域数据 worker_area
        saveWorkerAreas(param);
        // 5.存储param中的师傅服务种类数据 worker_category
        saveWorkerCategories(param);
        // 6.解析param中图片的信息,绑定师傅业务数据
        bindPicture(param,workerId);

        return workerId;
    }

    @Autowired(required=false)
    private AttachApi attachApi;
    @Autowired
    private WorkerConverter workerConverter;

    private void bindPicture(WorkerRegistParam param, Long workerId) throws BusinessException {

        // 1.从入参获取上传图片的信息
        List<IdCardParam> idCards = param.getAttachList();
        List<AttachUpdateParam> attachUpdateParamList = null;

        // 调用转换器 包装这个远程调用的参数
        attachUpdateParamList =
                workerConverter.assembleAttachParam(idCards,100,workerId.intValue());

        // 判断非空
        if(attachUpdateParamList == null){
            //参数错误
            throw new BusinessException(WorkerResultEnum.ATTACH_ARGS_ERROR);
        }else{
            try{
                attachApi.batchUpdateAttachByIdList(attachUpdateParamList);
            }catch (Exception e){
                // 可能rpc异常
                throw new BusinessException(WorkerResultEnum.ATTACH_UPDATE_FAILED);
            }

        }

    }


    @Autowired
    private WorkerCategoryRepository workerCategoryRepository;
    private void saveWorkerCategories(WorkerRegistParam param) {
        // 利用user_id作为条件,删除新增时已存在的种类数据
        workerCategoryRepository.delete(param.getUserId());
        // 新增数据(批量)
        workerCategoryRepository.saveWorkerCategories(param);
    }

    @Autowired
    private WorkerAreaRepository workerAreaRepository;
    private void saveWorkerAreas(WorkerRegistParam param) {
        // 利用user_id作为条件,删除新增时已存在的区域数据
        workerAreaRepository.delete(param.getUserId());
        // 新增数据(批量)
        workerAreaRepository.saveWorkerAreas(param);
    }

    private Long saveWorker(WorkerRegistParam param) {
        // 幂等逻辑: 同一个用户绑定多个师傅时,只保留一个师傅信息
        // 利用userId先删除历史数据.如果删除成功,说明注册过
        workerRepository.delete(param.getUserId());
        // 新增师傅
        Long workerId = workerRepository.save(param);

        return workerId;
    }

    private void checkIDCard() {
        // 使用正式的身份证号和真是姓名,验证是否合法,对接公安系统或大厂接口-阿里
        // 验证,没有问题,业务继续  有问题,直接抛出异常
        // 身份证号不能直接存数据库 - 脱敏
        // 41018219000622757x  --- 410182********2757x
    }

    /**
     * 获取用户id
     * @return userId
     */
    private Long getUserId() throws BusinessException {
        UserPrinciple user = LubanSecurityContext.getLoginToken();
        // 不一定能拿到登录用户
        if(user==null){
            throw new BusinessException(WorkerResultEnum.USER_TOKEN_VERIFY_FAILED);
        }
        return user.getId();
    }

    /**
     * 师傅详情
     * @return
     */
    public FrontWorkerBO detailWorker() throws BusinessException {
        // 1.获取当前登录userId
        Long userId = getUserId();
        log.info("当前登录的用户id:{}",userId);
        // 2.调用仓储层 利用userId查询师傅详情
        FrontWorkerBO frontWorkerBO = workerRepository.getWorkerByUserId(userId);
        // 3.判断BO对象是否为空(由于转换器的判断,do转bo时不会返回null,所以用其属性判断)
        if(frontWorkerBO.getId() == null){
            // 师傅为空(审核状态为3)
            frontWorkerBO.setAuditStatus(AuditStatusEnum.UNCREATED.getValue());
        }else{
            // 师傅不为空
            // 封装师傅 服务区域\种类
            putAreasAndCategories(frontWorkerBO);
            // 审核状态:0 1 2
            Integer auditStatus = frontWorkerBO.getAuditStatus();

            if(auditStatus==0){
                log.info("审核被驳回,填补拒绝原因");
                // 调用WorkerAuditRepository 查询被驳回的原因
                String reason = getLastRejectReason(userId);
                frontWorkerBO.setRejectReason(reason);
            } else if(auditStatus==1) {
                log.info("审核通过,查询账户余额");
                // RPC调用 查询account余额
                AccountDTO accountDTO = accountApi.getAccount(userId);
                FrontAccountBO frontAccountBO = new FrontAccountBO();
                frontAccountBO.setTotalAmount(accountDTO.getTotalAmount());
                frontWorkerBO.setFrontAccountBO(frontAccountBO);
            }

        }
        return frontWorkerBO;
    }

    private String getLastRejectReason(Long userId) throws BusinessException {
        // 1.调用仓储层 获取所有原因
        List<AdminAuditBO> auditLogs
                = workerAuditLogRepository.findAuditLogs(userId);
        // 2.可能为空
        if(CollectionUtils.isEmpty(auditLogs)){
            throw new BusinessException(WorkerResultEnum.SYSTEM_ERROR);
        }else{
            AdminAuditBO adminAuditBO = CollectionUtils.lastElement(auditLogs);
            // 拼接原因(拒绝原因+备注)
            String rejectReason = adminAuditBO.getRejectReason() +
                    ",具体为:" + adminAuditBO.getRemark();
            return rejectReason;
        }
    }

    private void putAreasAndCategories(FrontWorkerBO frontWorkerBO) {
        // 同一个用户ID
        Long userId = frontWorkerBO.getUserId();
        // 利用userId查询area categoey相关数据
        List<WorkerAreaBO> areasBOs =
                workerAreaRepository.findAreas(userId);
        List<WorkerCategoryBO> categoriesBO =
                workerCategoryRepository.findCategories(userId);
        // workerBO 添加属性
        frontWorkerBO.setWorkerAreaBOList(areasBOs);
        frontWorkerBO.setWorkerCategoryBOList(categoriesBO);
    }


    public ListRecordTotalBO<AdminWorkerBO> workerAuditList(WorkerListQuery query) {
        // 1.补齐查询参数(前端传参 - auditStatus=[0,2])
        putAuditStatusForQuery(query);
        // 2.利用query携带的条件查询总行数
        Long total = workerRepository.countWorker(query);
        ListRecordTotalBO<AdminWorkerBO> listTotal = null;
        if(total == 0){
            //查不到
            listTotal = new ListRecordTotalBO<>(null,total);
        }else{
            // 3.查询到数据,进行数据封装
            // 分页查询
            List<AdminWorkerBO> list = workerRepository.findPageWorkers(query);
            // 缺少区域 和 品类
            putWorkersAreasAndCategories(list);
            listTotal = new ListRecordTotalBO<>(list,total);
        }

        return listTotal;
    }

    private void putWorkersAreasAndCategories(List<AdminWorkerBO> list) {

        // 对 list循环(拿到每一条师傅数据)
        for(AdminWorkerBO adminWorkerBO : list){
            // 获取userId
            Long userId = adminWorkerBO.getUserId();
            // 利用userId查询区域和品类
            List<WorkerAreaBO> areas = workerAreaRepository.findAreas(userId);
            List<String> areaDetails = new ArrayList<>();
            for(WorkerAreaBO area : areas){
                areaDetails.add(area.getAreaDetail());
            }
            List<WorkerCategoryBO> categories = workerCategoryRepository.findCategories(userId);
            List<String> categoryDetails = new ArrayList<>();
            for(WorkerCategoryBO category : categories){
                categoryDetails.add(category.getCategoryDetail());
            }
            // 封装
            adminWorkerBO.setAreaDetails(areaDetails);
            adminWorkerBO.setCategoryDetails(categoryDetails);
        }
    }

    // 逻辑复用
    private void putWorkerAreasAndCategories(AdminWorkerBO adminWorkerBO){
        List<AdminWorkerBO> bos = new ArrayList<>();
        bos.add(adminWorkerBO);

        putWorkersAreasAndCategories(bos);
    }

    private void putAuditStatusForQuery(WorkerListQuery query) {
        List<Integer> auditStatus = query.getAuditStatus();
        if(CollectionUtils.isEmpty(auditStatus)){
            auditStatus.add(0); // 驳回
            auditStatus.add(2); // 未审核
        }
    }

    @Autowired
    private WorkerAuditLogRepository workerAuditLogRepository;

    /**
     * 封装待审核师傅详情
     */
    public AdminWorkerBO auditDetail(Long userId) throws BusinessException {

        // 1.使用userId查询师傅信息
        AdminWorkerBO adminWorkerBO = workerRepository.findAdminWorker(userId);
        // 判断
        if(adminWorkerBO.getId() == null){
            // 异常抛出
            // throw new BusinessException("1002","师傅不存在");
            throw new BusinessException(WorkerResultEnum.WORKER_NOT_FOUND);
        }

        // 2,3. 封装 area \ category
        putWorkerAreasAndCategories(adminWorkerBO);

        // 4.查询历史审核记录
        List<AdminAuditBO> auditLogs = workerAuditLogRepository.findAuditLogs(userId);
        adminWorkerBO.setWorkerAuditLogs(auditLogs);

        // 5.绑定图片
        putPictureUrls(adminWorkerBO);

        return adminWorkerBO;
    }

    @Value("${attach.url-prefix}")
    private String urlPrefix;

    private void putPictureUrls(AdminWorkerBO adminWorkerBO) throws BusinessException {
        // 构建查询对象
        AttachQuery attachQuery = new AttachQuery();
        // businessType; businessId;
        attachQuery.setBusinessType(100);
        attachQuery.setBusinessId(adminWorkerBO.getId().intValue());

        // 返回多张图片信息
        List<AttachDTO> dtos =
                attachApi.getAttachInfoByParam(attachQuery);
        // 图片路径
        List<String> urls = new ArrayList<>();

        // 处理查询结果
        if(CollectionUtils.isEmpty(dtos)){
            // 师傅图片为空
            throw new BusinessException(WorkerResultEnum.ATTACH_UPDATE_FAILED);
        }else{
            for(AttachDTO dto : dtos){
                String fileUuid = dto.getFileUuid();
                String url = urlPrefix + fileUuid;
                urls.add(url);
            }
        }
        // 封装
        adminWorkerBO.setAttachInfo(urls);

    }

    @Autowired
    private AccountApi accountApi;

    public Long auditSubmit(AuditSubmitParam param) throws BusinessException {
        // 1. workerId 实际还是userId,查询师傅的bo数据
        Long userId = param.getWorkerId();
        AdminWorkerBO adminWorker = workerRepository.findAdminWorker(userId);
        if(adminWorker.getId()==null){
            // 师傅不存在
            throw new BusinessException(WorkerResultEnum.WORKER_NOT_FOUND);
        }
        // 2.师傅不为空,获取当前师傅状态, 判断流转是否正常
        Integer currentAuditStatus = adminWorker.getAuditStatus();
        Integer targetAuditStatus = param.getAuditStatus();
        checkAuditStatusTransfer(currentAuditStatus,targetAuditStatus);

        // 3.新增日志审核记录(worker_audit_log)
        param.setUserId(param.getWorkerId());
        param.setUserName(adminWorker.getRealName());
        Long auditId = workerAuditLogRepository.save(param);

        // 4.更新师傅审核状态
        WorkerParam workerParam = new WorkerParam();
        workerParam.setAuditStatus(targetAuditStatus);
        workerParam.setUserId(userId);
        workerRepository.updateAuditStatus(workerParam);

        // 判断提交的审核状态和认证状态
        Integer certStatus = adminWorker.getCertStatus();
        if(targetAuditStatus==1 && certStatus==0){
            // 满足创建账户的要求
            workerParam.setCertStatus(1);
            workerRepository.updateCertStatus(workerParam);

            // 远程调用 account模块 创建账户
            AccountCreateParam accountCreateParam = new AccountCreateParam();
            accountCreateParam.setUserId(userId);
            accountCreateParam.setUserName(adminWorker.getRealName());
            accountCreateParam.setUserPhone(adminWorker.getPhone());
            Long account = accountApi.createAccount(accountCreateParam);
            log.info("创建账号:{}",account);
        }

        return auditId;
    }

    private void checkAuditStatusTransfer(
            Integer currentAuditStatus, Integer targetAuditStatus) throws BusinessException {
        // 0-驳回 1-通过 2-未审核
        // 0-0T 0-1T 1-0F 1-1F  2-0T 2-1T
        if(currentAuditStatus==1){
            throw new BusinessException(WorkerResultEnum.AUDIT_STATUS_TRANSFER_ERROR);
        }
    }
}
